/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  date.h
 *         \unit  date
 *        \brief  This is a simple date calculate module for C language
 *       \author  Lamdonn
 *      \version  v1.0.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#ifndef __date_H
#define __date_H

#include <stdint.h>
#include <stdio.h>

/* Version infomation */

#define DATE_V_MAJOR                        1
#define DATE_V_MINOR                        0
#define DATE_V_PATCH                        0

typedef struct {
    uint16_t year;                          /**< Year component of the date */
    uint8_t month;                          /**< Month component of the date */
    uint8_t day;                            /**< Day component of the date */
} DATE;

/**
 * \brief Macro to create a DATE structure instance.
 * \param[in] y: Year component of the date.
 * \param[in] m: Month component of the date (1-12).
 * \param[in] d: Day component of the date (1-31 depending on the month).
 * \return A DATE structure initialized with the specified year, month, and day.
 */
#define DATE(y, m, d) (DATE){.year=(y), .month=(m), .day=(d)}

/**
 * \brief Check if a year is a leap year.
 * \param[in] year: The year to check.
 * \return 1 if the year is a leap year, 0 otherwise.
 */
uint8_t date_isleap(uint16_t year);

/**
 * \brief Validate a date.
 * \param[in] date: The date structure to validate.
 * \return 1 if the date is valid, 0 otherwise.
 */
uint8_t date_isvalid(DATE date);

/**
 * \brief Get the number of days in a century.
 * \param[in] century: The century to evaluate.
 * \return Number of days in the given century.
 */
uint32_t date_century_days(uint16_t century);

/**
 * \brief Get the number of days in a year.
 * \param[in] year: The year to evaluate.
 * \return Number of days in the given year.
 */
uint32_t date_year_days(uint16_t year);

/**
 * \brief Get the number of days in a month of a given year.
 * \param[in] year: The year of the month.
 * \param[in] month: The month to evaluate (1-12).
 * \return Number of days in the specified month of the specified year.
 */
uint32_t date_month_days(uint16_t year, uint8_t month);

/**
 * \brief Get the day of week of a given date based on the total days.
 * \param[in] date: The date to evaluate.
 * \return The week number [1, 7] for the specified date (Mon | Tue | Wed | Thu | Fri | Sat | Sun), 0 if invalid.
 */
uint32_t date_get_dow(DATE date);

/**
 * \brief Calculate the total number of days from a given date to a base date.
 * \param[in] date: The date to calculate the total days for.
 * \return Total number of days from a base date to the given date, 0 if invalid.
 */
uint32_t date_current_days(DATE date);

/**
 * \brief Calculate the difference in days between two dates.
 * \param[in] date1: The first date.
 * \param[in] date2: The second date.
 * \return The difference in days between the two dates. Returns 0 if either date is invalid.
 */
int32_t date_diff_days(DATE date1, DATE date2);

/**
 * \brief Convert a number of days to a DATE structure.
 * \param[in] days: The number of days to convert.
 * \return A DATE structure representing the converted days.
 */
DATE date_from_days(uint32_t days);

/**
 * \brief Offset a date by a certain number of days.
 * \param[in] date: The date to offset.
 * \param[in] days: The number of days to offset (can be negative).
 * \return A new DATE structure after applying the offset, or a zero date if invalid.
 */
DATE date_offset(DATE date, int32_t days);

/**
 * \brief Show the calendar for a specific month and year.
 * \param[in] year: The year of the calendar to show.
 * \param[in] month: The month of the calendar to show.
 */
void date_calendar(uint16_t year, uint8_t month);

#endif
